package com.example.myproject.core;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import com.example.myproject.pojo.WriteBackData;
import com.example.myproject.util.*;

import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * 数据工厂。
 *
 * @author Jan
 * @date 2023/08
 */
public class DataFactory {

    private DataFactory() {

    }

    /**
     * 回写数据的集合。
     */
    private static final List<WriteBackData> WRITE_BACK_DATA = new ArrayList<>();

    /**
     * 运行和创建测试用例。
     *
     * @param ext ext 额外的拓展参数。
     * @throws Exception 异常。
     */
    public static void runAndCreateTestCases(JSONObject ext) throws Exception {
        // 获取请求示例。
        String jsonStr = FileUtils.readSampleRequest();
        // 解析json的字段数据类型及jsonPath。
        Set<String> jsonPaths = JsonPathParser.getJsonPaths(jsonStr);
        for (String jsonPath : jsonPaths) {
            // 字段数据类型。
            String filedDataType = JSONPath.read(jsonStr, jsonPath).getClass().getSimpleName();

            // 跳过复合类型。
            if ("JSONObject".equals(filedDataType)) {
                continue;
            }

            // 字段名。
            String[] split = jsonPath.split("\\.");
            String filedName = split[split.length - 1];

            // 通过反射生成对应数据类型的测试用例。
            List<Object> caseValues = DataFactory.getObjectArrayFromReflectType(CaseUtils.class, filedDataType);
            Map<String, String> caseNameAndRequestValueMap = new HashMap<>();

            for (Object value : caseValues) {
                String caseName = CaseUtils.createSpecifyCaseNameByCaseValue(filedName, value);
                // 修改字段值。
                JSONObject jsonObject = JsonUtils.checkAndSetJsonPathValue(jsonStr, jsonPath, value);
                caseNameAndRequestValueMap.put(caseName, jsonObject.toJSONString());
            }

            for (Map.Entry<String, String> entry : caseNameAndRequestValueMap.entrySet()) {
                String caseName = entry.getKey();
                String requestValue = "";
                if (null != ext) {
                    // 额外参数。
                    ext.put("title", caseName);
                    ext.put("case", JSON.parseObject(entry.getValue()));
                    requestValue = ext.toJSONString();
                } else {
                    requestValue = entry.getValue();
                }
                WRITE_BACK_DATA.add(new WriteBackData(caseName, requestValue));
            }
        }
        System.out.println("组装完成的用例数为 = " + WRITE_BACK_DATA.size());
        //开始回写
        ExcelUtils.initFileAndWriteDataToExcel(WRITE_BACK_DATA);
    }

    /**
     * 通过反射获取用例集合。
     *
     * @param clazz clazz
     * @param type  类型
     * @return {@link List}<{@link Object}>
     * @throws NoSuchMethodException     没有这样方法异常。
     * @throws InvocationTargetException 调用目标异常。
     * @throws InstantiationException    实例化异常。
     * @throws IllegalAccessException    非法访问异常。
     */
    private static List<Object> getObjectArrayFromReflectType(Class<? extends CaseUtils> clazz, String type) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Object obj = clazz.getConstructor().newInstance();
        String methodName = "get" + type + "TypeCases";
        Method method = clazz.getDeclaredMethod(methodName);
        Object invoke = method.invoke(obj);
        int length = Array.getLength(invoke);
        List<Object> caseValues = new ArrayList<>();
        for (int i = 0; i < length; i++) {
            caseValues.add(Array.get(invoke, i));
        }
        return caseValues;
    }
}
